STM32硬件SPI驱动OLED 您所在的位置:网站首页 oled 屏幕测试图 STM32硬件SPI驱动OLED

STM32硬件SPI驱动OLED

2023-08-14 20:01| 来源: 网络整理| 查看: 265

文章目录 一、OLED相关1、OLED简介2、0.96寸的OLED模块概述3、模块引脚说明4、汉字点阵编码原理 二、硬件SPI1、SPI简介2、SPI的引脚映射关系 三、SPI驱动的OLED1、实验要求2、实验环境3、实验结果(1)显示自己的学号和姓名(2)显示AHT20的温度和湿度(3)上下或左右的滑动显示长字符 四、总结

一、OLED相关 1、OLED简介

OLED即有机发光二级管(Organic Light-Emitting Diode,OLED)。OLED 显示技术具有自发光、广视角、几乎无穷高的对比度、较低耗电、极高反应速度、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优点,被认为是下一代的平面显示器新兴应用技术。

OLED 显示和传统的 LCD 显示不同,其可以自发光,所以不需要背光灯,这使得OLED 显示屏相对于LCD显示屏尺寸更薄,同时显示效果更优。

LCD都需要背光,而OLED不需要,因为它是自发光的。这样同样的显示,OLED效果要来得好一些。以目前的技术,OLED的尺寸还难以大型化,但是分辨率确可以做到很高。

2、0.96寸的OLED模块概述

模块背面图 在这里插入图片描述 该款OLED模块显示尺寸为0.96寸,拥有128x64分辨率。可以选择3线制、4线制SPI以及lIC三种通信方式,驱动IC为SSD1306。包含显示黑色、蓝色或者黄蓝双色三款模块。

具体说明如下:

A、使用4.7K电阻只焊接R3、R4电阻,则选择4线制SPI总线接口(默认)﹔B、使用4.7K电阻只焊接R2、R3电阻,则选择3线制SPI总线接口;C、使用4.7K电阻只焊接R1、R4、R6、R7、R8电阻,则选择IIC总线接口; 3、模块引脚说明

在这里插入图片描述

接口总线模式切换后,需要选择相应配套的软件和相应的接线引脚,模块才能正常运行。相应的接线引脚说明如下:

A、选择4线制SPI总线接口,所有的引脚都需要使用;

B、选择3线制SPI总线接口,只有DC引脚不需要使用(可以不接),其他引脚都需要使用;

C、选择IIC总线接口,只需要使用GND、VCC、D0、D1这四个引脚,同时将RES引脚接高电平(可以接VCC),将DC和CS引脚接电源地;

4、汉字点阵编码原理

汉字点阵编码

在汉字的点阵字库中,每个字节的每个位都代表一个汉字的一个点,每个汉字都是由一个矩形的点阵组成,0 代表没有点,1 代表有点,将 0 和 1 分别用不同颜色画出,就形成了一个汉字,常用的点阵矩阵有 12*12, 14*14, 16*16 三 种字库。

字库根据字节所表示点的不同有分为横向矩阵和纵向矩阵,目前多数的字库都是横向矩阵的存储方式(用得最多的应该是早期 UCDOS 字库),纵向矩阵一 般是因为有某些液晶是采用纵向扫描显示法,为了提高显示速度,于是便把字库 矩阵做成纵向,省得在显示时还要做矩阵转换。

OLED点阵显示

点阵屏像素按128列X64行组织,每一行128个像素单元的阴极是连接在一起,作为公共极(COM),每一列64个像素单元的阳极也连接在一起,作为一段(SEG)。行列交叉点上的LED就是一个显示单元,即一个像素。要点亮一个像素,只要在该像素所在列电极上加上正电压、行电极接地。同样,要驱动一整行图像,就需要同时把128列信号加载到列电极上,把该行行电极接地。该行显示时,其他63行均不能显示,其行电极应为高电平或悬空。

可见,整屏的显示,只能分时扫描进行,一行一行的显示,每次显示一行。行驱依次产生低电平扫描各行,列驱动读取显示数据依次加载到列电极上。扫描一行的时间称为行周期,完成一次全屏扫描,就叫做一帧。一般帧频大于60,人眼观察不到逐行显示。每行扫描显示用时叫占空比,占空比小,为达到相同的显示亮度,驱动电流就大。SSD1306段驱动最大电流为100uA,当整行128个像素全部点亮时,行电极就要流过12.8mA的电流。

二、硬件SPI

OLED 驱动方式

此模块支持四线 SPI、三线 SPI、IIC 接口和 6800、8080 并口方式,模块的通信接口是通过 BS0,BS1,BS2 三个管脚来配置。 在这里插入图片描述此处使用四线 SPI。 1、SPI简介 SPI是串行外设接口(Serial Peripheral Interface)的简写,其实就是一种总线通信协议,该总线以主从方式工作,通常是一个主设备和一个或多个从设备,一般需要4根线来进行数据通信,即SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选),相应的,有一套时序逻辑规定了通信过程。一般使用SPI的设备都配备了现成的SPI模块,只需要对相应的寄存器写入指令就可以进行通信了,如果没有SPI接口,也可以软件实现,就是根据时序图手动操作GPIO来实现通信,这就比较费劲了。 2、SPI的引脚映射关系

在这里插入图片描述

SS( Slave Select):从设备选择信号线,常称为片选信号线。SCK (Serial Clock):时钟信号线,用于通讯数据同步。MOSI (Master Output, Slave Input):主设备输出/从设备输入引脚。MISO(Master Input,,Slave Output):主设备输入/从设备输出引脚。 三、SPI驱动的OLED 1、实验要求

显示自己的学号和姓名;

显示AHT20的温度和湿度;

上下或左右的滑动显示长字符,比如歌词、诗词。(最好使用硬件刷屏模式)

2、实验环境

keil5编程软件

野火STM32F103指南者开发板

0.96寸的OLED模块

3、实验结果 (1)显示自己的学号和姓名

实验代码 测试例程下载地址: http://www.lcdwiki.com/zh/0.96inch_SPI_OLED_Module#.E7.A8.8B.E5.BA.8F.E4.B8.8B.E8.BD.BD 在这里插入图片描述 打开keil工程文件 在这里插入图片描述 利用取模软件,写好自已要显示的内容 在这里插入图片描述 取模时注意要设置参数 在这里插入图片描述

取模软件: PCtoLCD2002完美版.zip 提取码:jfbr

将生成的点阵添加进数组 在这里插入图片描述

注意:在添加字模时,要添加进汉字显示对应的数组。(此处我选择的是16 * 16大小的OLED汉字显示)

修改main.c如下

int main(void) { delay_init(); //延时函数初始化 NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 OLED_Init(); //初始化OLED OLED_Clear(0); //清屏(全黑) while(1) { TEST_MainPage(); //主界面显示测试 } }

修改test.c如下:

void TEST_MainPage(void) { GUI_ShowCHinese(28,20,16,"XX",1); //XX为名字 GUI_ShowString(4,48,"YY",16,1); //YY为学号 delay_ms(1500); delay_ms(1500); }

函数说明

GUI_ShowString() 的参数 参数一:X 坐标 参数二:Y 坐标 参数三:字符串(ASCLL码中的) 参数四:bit (表示字符显示格式,这里我用的 16 ,和汉字一样高) 参数五:显示样式(1:白字黑底;0:黑字白底)

GUI_ShowChinese() 的参数 参数一:X 坐标 参数二:Y 坐标 参数三:汉字点阵大小(这里使用的是 16×16 的,参数应该是 16) 参数四:要显示的汉字 参数五:显示样式(1:白字黑底;0:黑字白底)

编译运行生成.hex文件 在这里插入图片描述

屏幕显示 按照下图对应连接好STM32开发版和OLED模块 在这里插入图片描述

注:其中CS不接

连接好后如下图 在这里插入图片描述

将代码烧进板子里(.hex文件) 在这里插入图片描述 最终OLED模块显示如下图 在这里插入图片描述

(2)显示AHT20的温度和湿度

实验代码 AHT20的温湿度的读取工程:https://github.com/Thee24LYJ/STM32_AHT20 将AHT20 温湿度采集工程文件中的部分代码文件移植到OLED显示的工程文件中: 在这里插入图片描述在这里插入图片描述

在这里插入图片描述

注意要把文件路径添加进去 在这里插入图片描述 bsp_i2c.c修改如下

uint8_t t; u8 *strTemp1; u8 *strTemp2; u8 *strTemp3; u8 *strHumi1; u8 *strHumi2; u8 *strHumi3; void read_AHT20(void) { uint8_t i; //初始化 readByte 数组 for(i=0; i H1 = readByte[1]; //H1 左移 8 位并与 readByte[2] 相或 H1 = (H1 case 0:break; case 1:strTemp1 = "1";break; case 2:strTemp1 = "2";break; case 3:strTemp1 = "3";break; case 4:strTemp1 = "4";break; case 5:strTemp1 = "5";break; case 6:strTemp1 = "6";break; case 7:strTemp1 = "7";break; case 8:strTemp1 = "8";break; case 9:strTemp1 = "9";break; } t = (T1/10)%10; switch(t) { case 0:strTemp2 = "0";break; case 1:strTemp2 = "1";break; case 2:strTemp2 = "2";break; case 3:strTemp2 = "3";break; case 4:strTemp2 = "4";break; case 5:strTemp2 = "5";break; case 6:strTemp2 = "6";break; case 7:strTemp2 = "7";break; case 8:strTemp2 = "8";break; case 9:strTemp2 = "9";break; } t = T1%10; switch(t) { case 0:strTemp3 = "0";break; case 1:strTemp3 = "1";break; case 2:strTemp3 = "2";break; case 3:strTemp3 = "3";break; case 4:strTemp3 = "4";break; case 5:strTemp3 = "5";break; case 6:strTemp3 = "6";break; case 7:strTemp3 = "7";break; case 8:strTemp3 = "8";break; case 9:strTemp3 = "9";break; } t = H1/100; switch(t) { case 0:break; case 1:strHumi1 = "1";break; case 2:strHumi1 = "2";break; case 3:strHumi1 = "3";break; case 4:strHumi1 = "4";break; case 5:strHumi1 = "5";break; case 6:strHumi1 = "6";break; case 7:strHumi1 = "7";break; case 8:strHumi1 = "8";break; case 9:strHumi1 = "9";break; } t = H1/100; switch(t) { case 0:strHumi2 = "0";break; case 1:strHumi2 = "1";break; case 2:strHumi2 = "2";break; case 3:strHumi2 = "3";break; case 4:strHumi2 = "4";break; case 5:strHumi2 = "5";break; case 6:strHumi2 = "6";break; case 7:strHumi2 = "7";break; case 8:strHumi2 = "8";break; case 9:strHumi2 = "9";break; } t = H1/100; switch(t) { case 0:strHumi3 = "0";break; case 1:strHumi3 = "1";break; case 2:strHumi3 = "2";break; case 3:strHumi3 = "3";break; case 4:strHumi3 = "4";break; case 5:strHumi3 = "5";break; case 6:strHumi3 = "6";break; case 7:strHumi3 = "7";break; case 8:strHumi3 = "8";break; case 9:strHumi3 = "9";break; } GUI_ShowString(40,32," ",16,1); GUI_ShowString(40,48," ",16,1); GUI_ShowCHinese(0,32,16,"温度:",1); GUI_ShowString(40,32,strTemp1,16,1); GUI_ShowString(48,32,strTemp2,16,1); GUI_ShowString(56,32,".",16,1); GUI_ShowString(64,32,strTemp3,16,1); GUI_ShowCHinese(72,32,16,"℃",1); GUI_ShowCHinese(0,48,16,"湿度:",1); GUI_ShowString(40,48,strHumi1,16,1); GUI_ShowString(48,48,strHumi2,16,1); GUI_ShowString(56,48,".",16,1); GUI_ShowString(64,48,strHumi3,16,1); GUI_ShowCHinese(72,48,16,"%",1); }

oledfont.h中的修改如下

const typFNT_GB16 cfont16[] = { "温",0x00,0x00,0x23,0xF8,0x12,0x08,0x12,0x08,0x83,0xF8,0x42,0x08,0x42,0x08,0x13,0xF8, 0x10,0x00,0x27,0xFC,0xE4,0xA4,0x24,0xA4,0x24,0xA4,0x24,0xA4,0x2F,0xFE,0x00,0x00,/*"温",0*/ "度",0x01,0x00,0x00,0x80,0x3F,0xFE,0x22,0x20,0x22,0x20,0x3F,0xFC,0x22,0x20,0x22,0x20, 0x23,0xE0,0x20,0x00,0x2F,0xF0,0x24,0x10,0x42,0x20,0x41,0xC0,0x86,0x30,0x38,0x0E,/*"度",0*/ "湿",0x00,0x00,0x27,0xF8,0x14,0x08,0x14,0x08,0x87,0xF8,0x44,0x08,0x44,0x08,0x17,0xF8, 0x11,0x20,0x21,0x20,0xE9,0x24,0x25,0x28,0x23,0x30,0x21,0x20,0x2F,0xFE,0x00,0x00,/*"湿",0*/ ":",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,/*":",0*/ "℃",0x60,0x00,0x91,0xF4,0x96,0x0C,0x6C,0x04,0x08,0x04,0x18,0x00,0x18,0x00,0x18,0x00, 0x18,0x00,0x18,0x00,0x18,0x00,0x08,0x00,0x0C,0x04,0x06,0x08,0x01,0xF0,0x00,0x00,/*"℃",0*/ "%",0x00,0x00,0x18,0x04,0x24,0x08,0x24,0x10,0x24,0x20,0x24,0x40,0x24,0x80,0x19,0x00, 0x02,0x60,0x04,0x90,0x08,0x90,0x10,0x90,0x20,0x90,0x40,0x90,0x00,0x60,0x00,0x00,/*"%",0*/ };

主函数修改如下(main)

#include "delay.h" #include "sys.h" #include "oled.h" #include "gui.h" #include "test.h" #include "bsp_i2c.h" int main(void) { delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 OLED_Init(); //初始化OLED IIC_Init(); //初始化IIC OLED_Clear(0); //清屏(全黑) while(1) { read_AHT20_once(); //读取温度并显示 delay_ms(1500); } }

屏幕显示 在这里插入图片描述

(3)上下或左右的滑动显示长字符

实验代码 OLED屏的滚屏方式命令

水平左右滑动 OLED_WR_Byte(0x2E,OLED_CMD); //关闭滚动 OLED_WR_Byte(0x26,OLED_CMD); //水平向左或者右滚动 26/27 OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节 OLED_WR_Byte(0x00,OLED_CMD); //起始页 0 OLED_WR_Byte(0x07,OLED_CMD); //滚动时间间隔 OLED_WR_Byte(0x07,OLED_CMD); //终止页 7 OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节 OLED_WR_Byte(0xFF,OLED_CMD); //虚拟字节 OLED_WR_Byte(0x2F,OLED_CMD); //开启滚动 垂直和水平滚动 OLED_WR_Byte(0x2e,OLED_CMD); //关闭滚动 OLED_WR_Byte(0x29,OLED_CMD); //水平垂直和水平滚动左右 29/2a OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节 OLED_WR_Byte(0x00,OLED_CMD); //起始页 0 OLED_WR_Byte(0x07,OLED_CMD); //滚动时间间隔 OLED_WR_Byte(0x07,OLED_CMD); //终止页 1 OLED_WR_Byte(0x01,OLED_CMD); //垂直滚动偏移量 OLED_WR_Byte(0x2F,OLED_CMD); //开启滚动

参考:0.96oled屏,驱动ssd1306 一些不常用的命令用法和效果

修改mian函数(向左滑动)

#include "delay.h" #include "sys.h" #include "oled.h" #include "gui.h" #include "test.h" int main(void) { delay_init(); //延时函数初始化 NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 OLED_Init(); //初始化OLED OLED_Clear(0); //清屏(全黑) OLED_WR_Byte(0x2E,OLED_CMD); //关闭滚动 OLED_WR_Byte(0x27,OLED_CMD); //水平向左或者右滚动 26/27 OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节 OLED_WR_Byte(0x00,OLED_CMD); //起始页 0 OLED_WR_Byte(0x07,OLED_CMD); //滚动时间间隔 OLED_WR_Byte(0x07,OLED_CMD); //终止页 7 OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节 OLED_WR_Byte(0xFF,OLED_CMD); //虚拟字节 TEST_MainPage(); OLED_WR_Byte(0x2F,OLED_CMD); //开启滚动 }

显示数据函数

void TEST_MainPage(void) { GUI_ShowCHinese(10,20,16,"白头搔更短 浑欲不胜簪",2); delay_ms(1500); delay_ms(1500); }

用取模软件获取相应文字的点阵十六进制表示 在这里插入图片描述

const typFNT_GB16 cfont16[] = { "白",0x01,0x00,0x02,0x00,0x04,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08, 0x3F,0xF8,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x3F,0xF8,0x20,0x08,/*"白",0*/ "头",0x00,0x80,0x00,0x80,0x08,0x80,0x04,0x80,0x24,0x80,0x10,0x80,0x10,0x80,0x00,0x80, 0xFF,0xFE,0x01,0x00,0x01,0x40,0x02,0x20,0x04,0x10,0x08,0x08,0x30,0x04,0xC0,0x04,/*"头",1*/ "搔",0x20,0x00,0x23,0xF8,0x21,0x48,0x21,0x10,0xF8,0xA0,0x20,0x40,0x21,0xB0,0x2E,0x4E, 0x30,0x40,0xE3,0xF8,0x22,0x48,0x22,0x48,0x23,0xF8,0x20,0x44,0xA7,0xFC,0x40,0x04,/*"搔",2*/ "更",0x00,0x00,0xFF,0xFE,0x01,0x00,0x01,0x00,0x3F,0xF8,0x21,0x08,0x21,0x08,0x3F,0xF8, 0x21,0x08,0x21,0x08,0x3F,0xF8,0x11,0x00,0x0A,0x00,0x06,0x00,0x19,0xC0,0xE0,0x3E,/*"更",3*/ "短",0x20,0x00,0x21,0xFE,0x3C,0x00,0x50,0x00,0x90,0xFC,0x10,0x84,0x10,0x84,0xFE,0x84, 0x10,0xFC,0x10,0x00,0x10,0x84,0x28,0x44,0x24,0x48,0x44,0x00,0x41,0xFE,0x80,0x00,/*"短",4*/ "浑",0x00,0x00,0x23,0xFE,0x12,0x02,0x14,0x44,0x80,0x40,0x43,0xFC,0x48,0x80,0x08,0xA0, 0x11,0x20,0x11,0xFC,0xE0,0x20,0x20,0x20,0x27,0xFE,0x20,0x20,0x20,0x20,0x00,0x20,/*"浑",5*/ "欲",0x14,0x20,0x12,0x20,0x21,0x20,0x49,0x7E,0x08,0x42,0x14,0x84,0x22,0x10,0x41,0x10, 0xBE,0x10,0x22,0x10,0x22,0x28,0x22,0x28,0x22,0x48,0x3E,0x44,0x22,0x84,0x01,0x02,/*"欲",6*/ "不",0x00,0x00,0x7F,0xFC,0x00,0x80,0x00,0x80,0x01,0x00,0x01,0x00,0x03,0x40,0x05,0x20, 0x09,0x10,0x11,0x08,0x21,0x04,0x41,0x04,0x81,0x00,0x01,0x00,0x01,0x00,0x01,0x00,/*"不",7*/ "胜",0x00,0x20,0x78,0x20,0x49,0x20,0x49,0x20,0x49,0xFC,0x79,0x20,0x4A,0x20,0x48,0x20, 0x48,0x20,0x79,0xFC,0x48,0x20,0x48,0x20,0x48,0x20,0x48,0x20,0x4B,0xFE,0x98,0x00,/*"胜",8*/ "簪",0x20,0x40,0x3F,0x7E,0x48,0x90,0x85,0x08,0x3E,0x7C,0x08,0x10,0x48,0x90,0x7E,0xFE, 0x14,0x28,0x24,0x4A,0x46,0x86,0x3F,0xF8,0x20,0x08,0x3F,0xF8,0x20,0x08,0x3F,0xF8,/*"簪",9*/ };

放进对应数组 在这里插入图片描述

屏幕显示 编译运行,生成.hex文件并烧录 在这里插入图片描述 实验结果如下 在这里插入图片描述

四、总结

以上便是STM32硬件SPI驱动OLED的实验内容,通过此次试验,将SPI驱动和I2C驱动方式进行对比,发现SPI的速度要比I2C的传输速度更快,更适合用作高速传输通信。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有